package com.ruoyi.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.ruoyi.common.config.BigDataConfig;
import com.ruoyi.common.core.domain.FileObject;
import com.ruoyi.common.core.domain.IdName;
import com.ruoyi.common.core.domain.JSONObjectPro;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.common.enums.comlbs.*;
import com.ruoyi.common.exception.BigDataException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.http.BigDataResponse;
import com.ruoyi.common.utils.http.HttpRequest;
import com.ruoyi.system.domain.AlarmType;
import com.ruoyi.system.domain.EquipmentManagement;
import com.ruoyi.system.domain.RealtimePositioning;
import com.ruoyi.system.domain.VehicleManagement;
import com.ruoyi.system.domain.request.realtimevideo.AlarmDataParam;
import com.ruoyi.system.domain.request.relatimepositioning.MapDeviceExportParam;
import com.ruoyi.system.domain.request.relatimepositioning.RegionDeviceParam;
import com.ruoyi.system.domain.request.reportstatistics.OriginalTrajectoryParam;
import com.ruoyi.system.domain.vo.common.DeviceGps;
import com.ruoyi.system.domain.vo.equipment.EquipmentInfo;
import com.ruoyi.system.domain.vo.realtimepositioning.MapDeviceExport;
import com.ruoyi.system.domain.vo.realtimevideo.AlarmData;
import com.ruoyi.system.service.*;
import com.ruoyi.system.utils.ComLbsUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述 实时定位Service业务层处理
 * 作者 ZhangPing
 * 创建时间 2023/8/16 16:59
 */
@Slf4j
@Service
public class IRealtimePositioningServiceImpl implements IRealtimePositioningService {

    @Autowired
    private IVehicleManagementService vehicleManagementService;
    @Autowired
    private IEquipmentManagementService equipmentManagementService;
    @Autowired
    private IDriverInfoService driverInfoService;
    @Autowired
    private ISysDeptService deptService;
    @Autowired
    private IAlarmTypeService alarmTypeService;
    @Autowired
    private CommonService commonService;
    @Autowired
    private BigDataConfig bigDataConfig;

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public List<DeviceGps> originalTrajectory(OriginalTrajectoryParam param) {
        //组装大数据接口参数
        JSONObjectPro bigDataParams = new JSONObjectPro()
                .put("dvo", param.getDvo())
                .put("startTime", DateUtils.parseToTimestamp(param.getStartTime()))
                .put("endTime", DateUtils.parseToTimestamp(param.getEndTime()));

        //远程调用接口
        BigDataResponse response = HttpRequest.getBigDataNoEncode(bigDataConfig.getApiUrl() + "/dws/gps/list", bigDataParams, JSONObject.class);
        if (!response.isSuccess()) throw new BigDataException();

        // 提取分页数据
        BigDataResponse.PageData<JSONObject> pageData = response.getData();
        List<JSONObject> dataItems = pageData.getDataItems();

        if (ObjectUtils.isEmpty(dataItems)) return Collections.emptyList();
        //封装数据
        List<DeviceGps> resultList = dataItems.stream().map(ComLbsUtils::bigDataGpsFormat).collect(Collectors.toList());
        return resultList;
    }

    /**
     * 获取定位信息
     */
    @Override
    public RealtimePositioning queryLastGps(String deviceId) {

        JSONObjectPro httpParam = new JSONObjectPro()
                .put("dvo", deviceId);

        BigDataResponse  response = HttpRequest.getBigDataNoEncode(bigDataConfig.getApiUrl() + "/dws/device/status/list", httpParam, JSONObject.class);
        if (!response.isSuccess() || response.getData() == null) return vehicleManagementService.getPositionByDeviceId(deviceId);
        // 提取分页数据
        BigDataResponse.PageData<JSONObject> pageData = response.getData();
        List<JSONObject> dataItems = pageData.getDataItems();

        //查询设备
        EquipmentManagement equipment = equipmentManagementService.getByDeviceId(deviceId);
        if (equipment == null) throw new ServiceException("绑定的设备未录入!");
        if (equipment.getEquipmentType() == null) equipment.setEquipmentType(EquipmentTypeEnum.VEHICLE.getCode());


        RealtimePositioning realtimePositioning = equipmentManagementService.getVehiclePositionByDeviceId(deviceId);
        String driver = driverInfoService.getNameGroupByEquipmentId(realtimePositioning.getEquipmentId());
        if (StringUtils.isNotBlank(driver)) {
            String[] drivers = driver.split(",");
            realtimePositioning.setDriverName(drivers.length > 0 ? drivers[0] : "");
        }

        if (ObjectUtils.isNotEmpty(dataItems)) {
            DeviceGps gps = ComLbsUtils.bigDataGpsFormat(dataItems.get(0));
            //设置定位信息
            realtimePositioning.updateGpsData(gps);
            //更新sts数据
            realtimePositioning.updateStsData(gps.getSts());
            //更新车辆状态
            realtimePositioning.setVehicleStatus(ComLbsUtils.getVehicleStatus(gps).getCode());
            //更新卫星数量
            realtimePositioning.setSatelliteCount(gps.getSatelliteCount());
            //高程
            if (gps.getHgt() != null) {
                realtimePositioning.setHgt(Integer.parseInt(gps.getHgt().toString()));
            }
        }

        //设置基础信息
        RealtimePositioning detail = vehicleManagementService.getPositionByDeviceId(deviceId);
        realtimePositioning.updateBaseData(detail);
        //设置设备型号、设备类型、监管类型
        realtimePositioning.setEquipmentTypeStr(DictUtils.getDictLabel(DataDictTypeEnum.EQUIPMENT_TYPE.getText(), detail.getEquipmentType()));
        realtimePositioning.setDeviceModelStr(DictUtils.getDictLabel(DataDictTypeEnum.DEVICE_MODEL.getText(), detail.getDeviceModel()));
        realtimePositioning.setObjTypeName(DictUtils.getDictLabel(DataDictTypeEnum.OBJ_TYPE.getText(), detail.getObjType()));
        //设置公司名称
        List<SysDept> sysDepts = deptService.selectDeptList(new SysDept());
        Map<Long, SysDept> deptList = sysDepts.stream().collect(Collectors.toMap(SysDept::getDeptId, d -> d));
        SysDept parentDept = deptList.get(detail.getParentId());
        realtimePositioning.setParentId(detail.getParentId());
        if (parentDept != null) {
            realtimePositioning.setParentName(parentDept.getDeptName());
        }
        SysDept dept = deptList.get(detail.getCompanyId());
        if (dept != null) {
            realtimePositioning.setRemark(dept.getRemark());
        }
        //更新车辆任务状态
        realtimePositioning.setVehicleTaskStatus(detail.getVehicleTaskStatus());


//        String s;
        //卫星数量
//        Map popMap = (HashMap) gps.getPop();
//        s = PopMapEnum.SatelliteCount.getCode().toString();
//        if (popMap.containsKey(s)) {
//            realtimePositioning.setSatelliteCount(Integer.parseInt(popMap.get(s).toString()));
//        } else {
//            realtimePositioning.setSatelliteCount(0);
//        }
//        //信号强度
//        s = PopMapEnum.SignalIntensity.getCode().toString();
//        if (popMap.containsKey(s)) {
//            realtimePositioning.setSignalIntensity(Integer.parseInt(popMap.get(s).toString()));
//        } else {
//            realtimePositioning.setSignalIntensity(0);
//        }

        // 以下为北三字段
        //发送方id
//        s = PopMapEnum.SendId.getCode().toString();
//        if (popMap.containsKey(s)) {
//            realtimePositioning.setSendId(Long.parseLong(popMap.get(s).toString()));
//        }
//        //接收方id
//        s = PopMapEnum.ReceiveId.getCode().toString();
//        if (popMap.containsKey(s)) {
//            realtimePositioning.setReceiveId(Long.parseLong(popMap.get(s).toString()));
//        }
//        //定位状态
//        s = PopMapEnum.LocationState.getCode().toString();
//        if (popMap.containsKey(s)) {
//            int i = Integer.parseInt(popMap.get(s).toString());
//            LocationStateEnum locationStateEnum = LocationStateEnum.fromInt(i);
//            if (locationStateEnum != null) {
//                realtimePositioning.setLocationState(locationStateEnum.getText());
//            }
//        }
//        //短报文类型
//        s = PopMapEnum.ShortMsgType.getCode().toString();
//        if (popMap.containsKey(s)) {
//            int i = Integer.parseInt(popMap.get(s).toString());
//            ShortMsgTypeEnum shortMsgTypeEnum = ShortMsgTypeEnum.fromInt(i);
//            if (shortMsgTypeEnum != null) {
//                realtimePositioning.setShortMsgType(shortMsgTypeEnum.getText());
//            }
//        }
//        //短报文内容
//        s = PopMapEnum.ShortMsg.getCode().toString();
//        if (popMap.containsKey(s)) {
//            realtimePositioning.setShortMsg(popMap.get(s).toString());
//        }
//        //传感器数组
//        s = PopMapEnum.SensorList.getCode().toString();
//        if (popMap.containsKey(s)) {
//            realtimePositioning.setSensorList(JSON.parseArray(popMap.get(s).toString()));
//        }

        return realtimePositioning;
    }

    public List<JSONObjectPro> getMapDeviceList(Long orderStatus, Long companyId) {
        // 查询车辆列表
        EquipmentInfo equipmentInfo = new EquipmentInfo();
        // 查询所有状态 车辆状态 0空闲1任务中2在线3离线
        if (orderStatus == null) {
            equipmentInfo.setActivateStatus(ActivateStatusEnum.ACTIVATED.getCode());
            equipmentInfo.setCompanyId(companyId);
            equipmentInfo.setNumberPlateNotEmpty(true);
        } else {
            // 车辆状态 0空闲1任务中 2在线3离线
            equipmentInfo.setActivateStatus(ActivateStatusEnum.ACTIVATED.getCode());
            equipmentInfo.setCompanyId(companyId);
            if (orderStatus < 2) {
                equipmentInfo.setVehicleTaskStatus(orderStatus.intValue());
            }
            equipmentInfo.setNumberPlateNotEmpty(true);
        }

        List<EquipmentInfo> equipmentList = equipmentManagementService.selectList(equipmentInfo);
        // 获取车辆最新状态
        Map<String, DeviceGps> cache = commonService.getDeviceOnlineDataFromService();
        // 当前时间
        Date now = new Date();

        // 移除未定位过滤逻辑，所有车辆都参与处理
        List<JSONObjectPro> resultList = equipmentList.stream()
                .map(equipment -> {
                    JSONObjectPro item = new JSONObjectPro()
                            .put("equipmentId", equipment.getEquipmentId())
                            .put("numberPlate", equipment.getNumberPlate())
                            .put("deviceNo", equipment.getDeviceId())
                            .put("objectId", equipment.getVehicleId())
                            .put("companyId", equipment.getCompanyId().toString())
                            .put("companyName", equipment.getCompanyName())
                            .put("driverName", equipment.getDriverName())
                            .put("channelsNum", equipment.getChannels())
                            .put("objIcon", equipment.getObjIcon())
                            .put("objType", equipment.getObjType())
                            .put("vehicleTaskStatus", equipment.getVehicleTaskStatus())
                            .put("objTypeName", ObjectTypeEnum.fromInt(equipment.getObjType()).getText())
                            .put("type", OrgTypeEnum.DEVICE.getCode());

                    // 获取设备状态（可能为null）
                    DeviceGps device = cache.get(equipment.getDeviceId());
                    VehicleStatusEnum vehicleStatus = VehicleStatusEnum.POSITIONING_FAIL;

                    // 统一处理设备状态（包括null和未定位情况）
                    if (ObjectUtils.isEmpty(device)) {
                        // 设备无缓存数据时的默认值
                        setDefaultGpsValues(item);
                    } else {
                        // 有缓存数据时的状态计算
                        vehicleStatus = ComLbsUtils.getVehicleStatus(device);
                        if (vehicleStatus == VehicleStatusEnum.NOT_LOCATE) {
                            // 未定位状态的默认值
                            setDefaultGpsValues(item);
                        } else {
                            // 正常定位状态的真实值
                            boolean isOnline = device.getGte() != null && System.currentTimeMillis() - device.getGte() < VehicleStatusEnum.offlineTime;
                            item.put("lat", device.getLat())
                                    .put("lng", device.getLng())
                                    .put("gpsDateTime", device.getGdt())
                                    .put("spd", device.getSpd())
                                    .put("dre", device.getDre())
                                    .put("isOnline", isOnline ? OnlineStatusEnum.ONLINE.getCode() : OnlineStatusEnum.OFFLINE.getCode())
                                    .put("kilometer", device.getKilometer())
                                    .put("dayKMeter", device.getDayKMeter())
                                    .put("location", device.getLocation())
                                    .put("satelliteCount", device.getSatelliteCount())
                                    .put("hasAlarm", ObjectUtils.isNotEmpty(device.getAlm()));
                        }
                    }

                    // 统一设置状态和备注
                    item.put("vehicleStatus", vehicleStatus.getCode());
                    setRemarkByStatus(item, vehicleStatus, device, now);

                    return item;
                })
                .sorted(Comparator.comparing((JSONObject x) -> x.getString("gpsDateTime")).reversed())
                .collect(Collectors.toList());

        return resultList;
    }

    // 提取默认值设置逻辑为独立方法
    private void setDefaultGpsValues(JSONObjectPro item) {

        item.put("lat", 30.567514)
                .put("lng", 114.291939)
                .put("gpsDateTime", LocalDateTime.now().format(DATE_TIME_FORMATTER))
                .put("spd", 0)
                .put("dre", 0)
                .put("isOnline", OnlineStatusEnum.OFFLINE.getCode())
                .put("kilometer", 0)
                .put("dayKMeter", 0)
                .put("location", "湖北省武汉市江岸区六合路1号")
                .put("satelliteCount", 0)
                .put("hasAlarm", false);
    }

    // 提取备注设置逻辑为独立方法
    private void setRemarkByStatus(JSONObjectPro item, VehicleStatusEnum vehicleStatus, DeviceGps device, Date now) {
        switch (vehicleStatus) {
            case DRIVING:
                item.put("remark", device != null ? device.getSpd() + "km/h" : "定位失败");
                break;
            case OFFLINE:
                if (device != null) {
                    item.put("remark", "离线" + DateUtils.timeDistance(now, DateUtils.parseDate(device.getGdt())));
                } else {
                    item.put("remark", "离线状态未知");
                }
                break;
            case POSITIONING_FAIL:
                item.put("remark", "定位失败");
                break;
            case NOT_LOCATE:
                item.put("remark", "未定位");
                break;
            default:
                item.put("remark", vehicleStatus.getText());
        }
    }
    /**
     * 获取设备实时视频通道号
     * @return
     */
    @Override
    public String[] realtimeDeviceVideoList(String deviceId){
        EquipmentManagement equipment = equipmentManagementService.getByDeviceId(deviceId);
        if (equipment == null) throw new ServiceException("无该设备！");
        String channelsNum = equipment.getChannelsNum();
        if (StringUtils.isEmpty(channelsNum)) throw new ServiceException("该设备无视频通道！");
        String[] channels = channelsNum.split(",");
        Arrays.sort(channels);
        return channels;
    }

    /**
     * 区域查车
     * @param param
     * @return
     */
    @Override
    public Object regionDeviceList(RegionDeviceParam param){
        if (DateUtils.parseDate(param.getStartTime()).after(DateUtils.parseDate(param.getEndTime()))){
            throw new ServiceException("开始时间不能大于结束时间！");
        }
        JSONObjectPro bigDataParam = new JSONObjectPro()
                .put("type", param.getType())
                .put("startTime", param.getStartTime())
                .put("endTime", param.getEndTime())
                .put("pointList", param.getPoints())
                .put("companyIdList", deptService.selectPermissionDeptId(param.getDeptId()).stream().map(Object::toString).collect(Collectors.toList()));
        if (param.getType() == RegionTypeEnum.CIRCLE.getCode()){
            bigDataParam.put("distance", param.getRadius()).put("circle", new Double[]{param.getCirclePoint().getLat(), param.getCirclePoint().getLng()});
        }
        BigDataResponse<List<Map<String, Object>>> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/gpsRelationData/queryPolygonDvoGeoInfo", bigDataParam, ArrayList.class);
        if (!response.isSuccess()) throw new BigDataException();
        return response.getData();
    }

    /**
     * 设备数据导出
     * @return
     */
    @Override
    public List<MapDeviceExport> mapDeviceExport(MapDeviceExportParam param){
        //查询车辆列表
        List<VehicleManagement> vehicleList = vehicleManagementService.listMapVehicle(new VehicleManagement());
        //获取车辆最新状态
        Map<String, DeviceGps> cache = commonService.getDeviceOnlineDataFromCache();
        List<MapDeviceExport> resultList = vehicleList.stream().filter(vehicle -> param.getDeviceIds().contains(vehicle.getDeviceId())).map(i -> {
            DeviceGps device = cache.get(i.getDeviceId());
            if (device != null) {
                return new MapDeviceExport()
                        .setDeviceNo(device.getDvo())
                        .setCompanyName(i.getCompanyName())
                        .setNumberPlate(i.getNumberPlate())
                        .setGdt(device.getGdt())
                        .setSpd(device.getSpd())
                        .setKilometer(device.getKilometer())
                        .setSatelliteCount(device.getSatelliteCount())
                        .setLocation(device.getLocation());
            }else {
                return new MapDeviceExport()
                        .setDeviceNo("N/A")
                        .setCompanyName(i.getCompanyName())
                        .setNumberPlate(i.getNumberPlate())
                        .setGdt("无数据")
                        .setSpd(0)
                        .setKilometer(0.0)
                        .setSatelliteCount(0)
                        .setLocation("未知位置");
            }
        }).collect(Collectors.toList());
        return resultList;
    }

    /**
     * 获取报警数据列表
     * @param params
     * @return
     */
    @Override
    public List<AlarmData> alarmDataList(AlarmDataParam params){
        //获取报警类型集合
        Map<Integer, String> alarmTypeMap = alarmTypeService.selectList(new AlarmType()).stream().collect(Collectors.toMap(AlarmType::getType, AlarmType::getName, (var1, var2) -> var1));
        //组装大数据接口请求参数
        JSONObjectPro paramMap = new JSONObjectPro();
        if (com.ruoyi.common.utils.StringUtils.isNotEmpty(params.getDvo())){
            paramMap.put("dvo", params.getDvo());
        }
        if (params.getAlarmType() != null){
            paramMap.put("alarmTypes", params.getAlarmType());
        } else {
            paramMap.put("alarmTypes", alarmTypeMap.keySet());
        }
        if (com.ruoyi.common.utils.StringUtils.isNotEmpty(params.getStartTime())) {
            paramMap.put("startTime", DateUtils.parseToTimestamp(params.getStartTime()));
        }
        if (com.ruoyi.common.utils.StringUtils.isNotEmpty(params.getEndTime())) {
            paramMap.put("endTime", DateUtils.parseToTimestamp(params.getEndTime()));
        }

        BigDataResponse response = HttpRequest.getBigDataNoEncode(bigDataConfig.getApiUrl() + "/dwd/device/alarm/list", paramMap,JSONObject.class);

        if (!response.isSuccess()) throw new BigDataException();

        // 提取分页数据
        BigDataResponse.PageData<JSONObject> pageData = response.getData();
        List<JSONObject> dataItems = pageData.getDataItems();

        List<AlarmData> resultList = new ArrayList<>();
        if (response.isSuccess() && ObjectUtils.isNotEmpty(dataItems)){
            resultList = dataItems.stream().map(x -> {
                JSONObject item= JSONObject.from(x);
                AlarmData alarmData = new AlarmData()
                        .setNumberPlate(item.getString("numberPlate"))
                        .setAddress(item.getString("address"))
                        .setDeviceId(item.getString("dvo"))
                        .setLng(item.getDouble("lng"))
                        .setLat(item.getDouble("lat"))
                        .setSpd(item.getString("spd"))
                        .setAlarmType(item.getInteger("alarmType"));
//                        .setAmc(item.getString("amc"));
                if (item.get("gte") != null) alarmData.setStartTime(new Date(item.getLong("gte")));
                if (com.ruoyi.common.utils.StringUtils.isEmpty(alarmTypeMap.get(alarmData.getAlarmType()))) alarmData.setAlarmTypeName("未知");
                else alarmData.setAlarmTypeName(alarmTypeMap.get(alarmData.getAlarmType()));
                return alarmData;
            }).collect(Collectors.toList());
        }
        return resultList;
    }
}
